#include "Common.h"

initSing(QuestHandler);

void QuestHandler::LoadQuestRelations()
{
	QResult* res = CharacterDatabase.SafeQuery("select * from npc_quest_start order by npcentry asc");
	if(!res)
		return;
	if(!res->NumRows())
	{
		Log->Notice("SQLStorage", "Loaded 0 records from table npc_quest_start");
		return;
	}
	NPCQuestStart* n = new NPCQuestStart;
	n->entry = res->Fetch()[0];
	ui32 oldentry = n->entry;
	ui32 count = 0;
	do
	{
		ui32 newentry = res->Fetch()[0];
		if(newentry != oldentry)
		{
			NPCQuestStartStorage[oldentry] = n;
			n = new NPCQuestStart;
			n->entry = newentry;
			oldentry = newentry;
		}
		n->questentries.insert(res->Fetch()[1].GetUI32());
		++count;
	}
	while(res->NextRow());
	Log->Notice("SQLStorage", "Loaded %u questgivers with %u quests", NPCQuestStartStorage.size(), count);
}

ui8 QuestHandler::CalculateQuestStatus(ui32 questentry, Player* pPlayer)
{
	Quest* qst = miscmgr->GetQuestInfo(questentry);
	if(!qst)
		return 0;

	if(pPlayer->HasQuestFinished(questentry)) // Normally we dont do quests multiple times :D
		return 0;

	if(pPlayer->IsAtQuest(questentry)) // gray questionmark cause were at the quest
		return 5;

	if(pPlayer->GetLevel() > qst->questlevel + 10) // low-level quests are only displayed if we talk to the npc
		return 2;

	if(pPlayer->GetMoney() < qst->required_money) // id say we dont display quests with money at all if we dont have the coins
		return 0;

	if(pPlayer->GetLevel() + 5 < qst->minlevel) // Only display the gray mark if were at least 5 lvl near the minlvl
		return 0;

	if(pPlayer->GetLevel() < qst->minlevel)
		return 1;

	if(!pPlayer->HasQuestFinished(qst->preq1) || !pPlayer->HasQuestFinished(qst->preq2) ||
		!pPlayer->HasQuestFinished(qst->preq3) || !pPlayer->HasQuestFinished(qst->preq4) ||
		!pPlayer->HasQuestFinished(qst->preq5) || !pPlayer->HasQuestFinished(qst->preq6)) // just extend that if you need more!
		return 0;
	return 8;

}

ui8 QuestHandler::GetAvailableQuests(set<ui32>& quests, Player* target)
{
	set<ui32>::iterator itr = quests.begin();
	set<ui32>::iterator end = quests.end();

	ui8 count = 0;
	for( ; itr != end; ++itr)
	{
		ui8 status = CalculateQuestStatus(*itr, target);
		if(status == 8 || status == 2)
			++count;
	}
	return count;
}

void Session::HandleQuestNpcQuery(RealmPacket& data)
{
	RealmPacket out(SMSG_QUESTGIVER_STATUS);
	ui64 guid;
	data >> guid;
	Creature* cr = m_player->GetMapHandler()->GetCreature(guid);
	if(!cr)
		return;

	NPCQuestStart* nqs = sQuestHandler.GetStartingRelation(cr->GetEntry());
	if(!nqs)
		return;

	ui32 status = 0;
	set<ui32>::iterator itr = nqs->questentries.begin();
	set<ui32>::iterator end = nqs->questentries.end();

	for( ; itr != end; ++itr)
	{
		ui32 temp = sQuestHandler.CalculateQuestStatus(*itr, m_player);
		if(temp > status) // higher status == better :D
			status = temp;
	}
	out << guid << status;
	SendPacket(&out);
}

void Session::HandleQuestGiverHello(RealmPacket& data)
{
	ui64 guid;
	data >> guid;
	Creature* cr = m_player->GetMapHandler()->GetCreature(guid);
	if(!cr)
		return;
	NPCQuestStart* qst = sQuestHandler.GetStartingRelation(cr->GetEntry());
	if(!qst)
		return;
	RealmPacket out(SMSG_QUESTGIVER_QUEST_LIST);
	TextRelation* rel = miscmgr->GetTextRelation(cr->GetEntry());
	char* text = 0;
	if(rel)
	{
		GossipText* gtext = miscmgr->GetGossipText(rel->textid);
		if(gtext)
			text = gtext->text;
	}
	out << cr->GetGUID();
	if(text)
		out << text;
	else
		out << "Hey there, $N! How can I help you?";

	out << ui32(1) << ui32(1);
	out << ui8(sQuestHandler.GetAvailableQuests(qst->questentries, m_player));
	set<ui32> ::iterator itr = qst->questentries.begin();
	set<ui32> ::iterator end = qst->questentries.end();

	for( ; itr != end; ++itr)
	{
		ui8 status = sQuestHandler.CalculateQuestStatus(*itr, m_player);
		if(status != 8 && status != 5)
			continue;
		Quest* q = miscmgr->GetQuestInfo((*itr));
		out << (*itr);
		switch(status)
		{
		case 5:
			out << ui32(4) << ui32(0);
			break;
		case 10:
			out << ui32(4) << ui32(1);
			break;
		case 2:
			out << ui32(8) << ui32(0);
			break;
		default:
			out << ui32(status) << ui32(0);
			break;
		}
		
		out << q->title;
	}
	
	SendPacket(&out);
}

void Session::HandleQuestQuery(RealmPacket& data)
{
	ui64 guid;
	ui32 questid;
	data >> guid >> questid;
	Quest* q = miscmgr->GetQuestInfo(questid);
	if(!q)
		return;
	RealmPacket out(SMSG_QUESTGIVER_QUEST_DETAILS);
	out << guid << ui32(0) << ui32(0) << q->entry;
	out << q->title << q->main_text << q->objectives;
	out << ui32(1) << q->needed_players << ui8(0) << ui8(0);
	out << q->GetNumRewardChoice();

	for(ui32 i = 0; i < 6; ++i)
	{
		if(!q->rewardchoice[i])
			continue;
		ItemInfo* inf = miscmgr->GetItemInfo(q->rewardchoice[i]);
		out << q->rewardchoice[i] << q->rewardchoicecount[i];
		if(inf)
			out << inf->DisplayInfoID;
		else
			out << ui32(0);
	}

	out << q->GetNumReward();
	
	for(ui32 i = 0; i < 4; ++i)
	{
		if(!q->rewardfix[i])
			continue;
		ItemInfo* inf = miscmgr->GetItemInfo(q->rewardfix[i]);
		out << q->rewardfix[i] << q->rewardfixcount[i];
		if(inf)
			out << inf->DisplayInfoID;
		else
			out << ui32(0);
	}

	out << q->reward_money << q->rewarded_honor << q->learned_spell;
	out << q->casted_spell << q->rewartitle << q->rewardtalents;
	out << ui32(0);
	SendPacket(&out);
}

void Session::HandleQuestAccept(RealmPacket& data)
{
	ui64 guid;
	ui32 qentry;
	data >> guid >> qentry;
	ui8 res = m_player->AddQuest(qentry);
	if(res == 25)
	{
		RealmPacket full(SMSG_QUESTLOG_FULL);
		SendPacket(&full);
	}
	m_player->UpdateQuest(res);
	sQuestHandler.UpdateNearbyQuestgivers(m_player);
}

void Session::HandleQuestNewQuestQuery(RealmPacket& data)
{
	ui32 entry;
	data >> entry;
	Quest* q = miscmgr->GetQuestInfo(entry);
	if(!q)
		return;
	
	RealmPacket out(SMSG_QUEST_QUERY_RESPONSE);
	out << entry << ui32(2) << ui32(q->questlevel);

	if(q->questsort)
		out << i32(-(i32)q->questsort);
	else
		out << ui32(q->zoneid);

	out << q->questtype << q->needed_players;
	out << q->required_faction << q->required_reputation;
	out << ui32(0) << ui32(0);
	out << ui32(0) << q->reward_money;
	out << q->required_money << q->casted_spell;
	out << q->learned_spell << q->rewarded_honor;
	out << q->srcitem << q->flags;
	out << q->rewartitle << ui32(0);
	out << q->rewardtalents;

	for(int i = 0; i < 4; ++i)
		out << q->rewardfix[i] << q->rewardfixcount[i];

	for(int i = 0; i < 6; ++i)
		out << q->rewardchoice[i] << q->rewardchoicecount[i];

	out << q->point_mapid << q->point_x;
	out << q->point_y << q->point_opt;
	
	out << q->title << q->objectives << q->main_text << q->completion;

	for(int i = 0; i < 4; ++i)
		out << q->requirednpc[i] << q->requirednpccount[i] << ui32(0);

	for(int i = 0; i < 4; ++i)
		out << q->requireditem[i] << q->requireditemcount[i];

	out << ui32(0) << ui32(0);

	out << q->objectives1 << q->objectives2 << q->objectives3 << q->objectives4;

	SendPacket(&out);
}

void QuestHandler::UpdateNearbyQuestgivers(Player* target)
{
	if(!target)
		return;

	set<Object*>::iterator itr = target->GetInRangeSetBegin();
	set<Object*>::iterator end = target->GetInRangeSetEnd();

	for( ; itr != end; ++itr)
	{
		if((*itr)->GetTypeId() != TYPEID_UNIT)
			continue;
		Creature* cr = ((Creature*)(*itr));
		if(!cr->HasFlag(NPC_FLAG_QUESTGIVER))
			continue;
		NPCQuestStart* nqs = GetStartingRelation(cr->GetEntry());
		if(!nqs)
			continue;
		set<ui32>::iterator initr = nqs->questentries.begin();
		set<ui32>::iterator inend = nqs->questentries.end();
		
		ui32 status = 0;
		for( ; initr != inend; ++initr)
		{
			ui32 tmp = CalculateQuestStatus((*initr), target);
			if(tmp > status)
				status = tmp;
		}
		RealmPacket data(SMSG_QUESTGIVER_STATUS);
		data << cr->GetGUID() << status;
		target->GetSession()->SendPacket(&data);
	}
}